﻿using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Reflection;

namespace sinetd
{
    public class Manager<T> where T : class, IManagerElement
    {
        public static T Create(string name)
        {
            GetDictionary();

            if (types.ContainsKey(name))
            {
                T plugin = types[name].Assembly.CreateInstance(types[name].FullName) as T;
                instances.Add(plugin.Id, plugin);
                return plugin;
            }
            return null;
        }

        public static T Create(string name, string id)
        {
            GetDictionary();

            if (types.ContainsKey(name))
            {
                T plugin = types[name].Assembly.CreateInstance(types[name].FullName) as T;
                instances.Add(id != "" ? id : plugin.Id, plugin);
                return plugin;
            }
            return null;
        }

        public static T GetById(string id)
        {
            GetDictionary();

            if (instances.ContainsKey(id))
                return instances[id];
            return null;
        }

        public static T GetOrCreate(string name, string id)
        {
            T plugin = GetById(id);
            if (plugin == null)
                plugin = Create(name, id);
            return plugin;
        }

        public static List<string> GetNames()
        {
            GetDictionary();

            return types.Keys.ToList();
        }

        public static List<string> GetIds()
        {
            GetDictionary();

            return instances.Keys.ToList();
        }

        private static Dictionary<string, T> instances;
        private static Dictionary<string, Type> types;

        public static Dictionary<string, Type> GetDictionary()
        {
            if (types == null)
            {
                instances = new Dictionary<string, T>();
                types = new Dictionary<string, Type>();

                IEnumerable<string> files = Directory.EnumerateFiles(Directory.GetCurrentDirectory() + Path.DirectorySeparatorChar + "plugin" + Path.DirectorySeparatorChar, "sinetd.*.dll");
                foreach (string file in files)
                {
                    Assembly asm = Assembly.Load(AssemblyName.GetAssemblyName(file));
                    try
                    {
                        foreach (Type t in asm.GetTypes())
                        {
                            if (t.IsClass)
                            {
                                try
                                {
                                    T plugin = asm.CreateInstance(t.FullName) as T;
                                    if (plugin != null)
                                    {
                                        types.Add(plugin.Name, t);
                                    }
                                }
                                catch { }
                            }
                        }
                    }
                    catch { }
                }
            }

            return types;
        }
    }
}
